package com.tabjin.rfidsocket.service.sys.impl;

import com.google.common.base.Preconditions;
import com.tabjin.rfidsocket.common.RequestHolder;
import com.tabjin.rfidsocket.common.utils.BeanValidator;
import com.tabjin.rfidsocket.exception.ParamException;
import com.tabjin.rfidsocket.mapper.mapper.SysDeptCustomMapper;
import com.tabjin.rfidsocket.mapper.mapper.SysDeptMapper;
import com.tabjin.rfidsocket.mapper.mapper.SysUserCustomMapper;
import com.tabjin.rfidsocket.pojo.SysDept;
import com.tabjin.rfidsocket.pojo.bo.SysDeptBO;
import com.tabjin.rfidsocket.pojo.vo.SysDeptVO;
import com.tabjin.rfidsocket.service.sys.SysDeptService;
import com.tabjin.rfidsocket.utils.LevelUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @author tabjin
 * create at 2020/12/8 11:21
 * @program rfid_socket
 * @description
 */
@Service
public class SysDeptServiceImpl implements SysDeptService {

    final static Logger logger = LoggerFactory.getLogger(SysDeptServiceImpl.class);


    private final SysDeptMapper sysDeptMapper;

    private final SysDeptCustomMapper sysDeptCustomMapper;

    private final SysUserCustomMapper sysUserCustomMapper;

    public SysDeptServiceImpl(SysDeptMapper sysDeptMapper, SysDeptCustomMapper sysDeptCustomMapper, SysUserCustomMapper sysUserCustomMapper) {
        this.sysDeptMapper = sysDeptMapper;
        this.sysDeptCustomMapper = sysDeptCustomMapper;
        this.sysUserCustomMapper = sysUserCustomMapper;
    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public SysDeptVO add(SysDeptBO sysDeptBO) {
//        BeanValidator.check(sysDeptBO);
//        if (checkExist(sysDeptBO.getParentId(), sysDeptBO.getName(), sysDeptBO.getId())) {
        if (checkExist(sysDeptBO.getParentId(), sysDeptBO.getName(), sysDeptBO.getId())) {
            logger.error("新增部门 同一级存在相同名称的部门");
            throw new ParamException("同一级存在相同名称的部门");
        }

        SysDept sysDept = SysDept.builder()
                .name(sysDeptBO.getName())
                .parentId(sysDeptBO.getParentId())
                .seq(sysDeptBO.getSeq())
                .remark(sysDeptBO.getRemark())
                .build();

        sysDept.setLevel(LevelUtil.calculateLevel(getLevel(sysDeptBO.getParentId()), sysDeptBO.getParentId()));

//        sysDept.setOperator("system");// TODO
//        sysDept.setOperator(RequestHolder.getCurrentUser().getUsername());// 取出当前登录用户
        sysDept.setOperator("张进");// 取出当前登录用户
        sysDept.setOperateIp("127.0.0.1");// TODO
        sysDept.setOperateTime(new Date());

        sysDeptMapper.insertSelective(sysDept);

        SysDeptVO vo = new SysDeptVO();
        BeanUtils.copyProperties(sysDept, vo);
        return vo;
    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void update(SysDeptBO sysDeptBO) {
        BeanValidator.check(sysDeptBO);
        if (checkExist(sysDeptBO.getParentId(), sysDeptBO.getName(), sysDeptBO.getId())) {
            logger.error("更新部门 同一级存在相同名称的部门");
            throw new ParamException("同一级存在相同名称的部门");
        }

        SysDept before = sysDeptMapper.selectByPrimaryKey(sysDeptBO.getId());
        Preconditions.checkNotNull(before, "待更新部门不存在");

        SysDept after = SysDept.builder()
                .id(sysDeptBO.getId())
                .name(sysDeptBO.getName())
                .parentId(sysDeptBO.getParentId())
                .seq(sysDeptBO.getSeq())
                .remark(sysDeptBO.getRemark())
                .build();
        after.setLevel(LevelUtil.calculateLevel(getLevel(sysDeptBO.getParentId()), sysDeptBO.getParentId()));
//        after.setOperator("system-update");// TODO
        after.setOperator(RequestHolder.getCurrentUser().getUsername());// 取出当前登录用户
        after.setOperateIp("127.0.0.1");// TODO
        after.setOperateTime(new Date());

        updateWithChild(before, after);
    }

    /**
     * 删除部门
     *
     * @param deptId
     */
    @Override
    public void delete(Integer deptId) {
        SysDept sysDept = sysDeptMapper.selectByPrimaryKey(deptId);
        Preconditions.checkNotNull(sysDept, "待删除的部门不存在");
        // 是否有子部门和用户
        if (sysDeptCustomMapper.countByParentId(deptId) > 0) {
            throw new ParamException("当前部门下有子部门，无法直接删除");
        }
        if (sysUserCustomMapper.countByDeptId(deptId) > 0) {
            throw new ParamException("当前部门下有用户，无法直接删除");
        }

        // 删除部门
        sysDeptMapper.deleteByPrimaryKey(deptId);
    }

    /**
     * 部门是有层级的，需要递归
     *
     * @param before 之前的部门信息
     * @param after  更新后的部门信息
     */
    @Transactional
    void updateWithChild(SysDept before, SysDept after) {
        // 子部门是否需要更新
        String newLevelPrefix = after.getLevel();
        String oldLevelPrefix = before.getLevel();
        if (!after.getLevel().equals(before.getLevel())) {// 不一致才需要进行子部门的更新
            // 当前部门的子部门
            List<SysDeptVO> deptList = sysDeptCustomMapper.getChildDeptListByLevel(before.getLevel());
            if (CollectionUtils.isNotEmpty(deptList)) {// 子部门不为空
                for (SysDeptVO deptVO : deptList) {
                    String level = deptVO.getLevel();// 当前部门的level
                    if (level.indexOf(oldLevelPrefix) == 0) {
                        level = newLevelPrefix + level.substring(oldLevelPrefix.length());
                        deptVO.setLevel(level);
                    }
                }
                // 批量更新部门level
                sysDeptCustomMapper.batchUpdateLevel(deptList);
            }
        }
        sysDeptMapper.updateByPrimaryKey(after);
    }

    /**
     * 判断数据是否有重复
     *
     * @param parentId
     * @param deptName
     * @param deptId   当前部门的id
     * @return
     */
    private boolean checkExist(Integer parentId, String deptName, Integer deptId) {
        return sysDeptCustomMapper.countByNameAndParentId(parentId, deptName, deptId) > 0;
    }

    /**
     * 获取部门level
     *
     * @param deptId 部门id
     * @return
     */
    private String getLevel(Integer deptId) {
        SysDept dept = sysDeptMapper.selectByPrimaryKey(deptId);
        if (dept == null) {
            return null;
        }
        return dept.getLevel();
    }
}
